#include "widget_node_attachment.h"
#include "ui_widget_node_attachment.h"
#include "../entity/EntitySceneNode.h"
#include "../AvatarLibrary.h"
#include <QMessageBox>

WidgetNodeAttachment::WidgetNodeAttachment(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::WidgetNodeAttachment)
{
    ui->setupUi(this);
    QDoubleValidator* val = new QDoubleValidator(this);
    val->setDecimals(6);
    val->setNotation(QDoubleValidator::StandardNotation);
    ui->lineEditPosX->setValidator(val);
    ui->lineEditPosY->setValidator(val);
    ui->lineEditPosZ->setValidator(val);
    ui->lineEditRotX->setValidator(val);
    ui->lineEditRotY->setValidator(val);
    ui->lineEditRotZ->setValidator(val);
    connect(ui->comboBoxAnimation, &QComboBox::currentIndexChanged, this, &WidgetNodeAttachment::comboBoxAnimation_currentIndexChanged);
    connect(ui->comboBoxJoint, &QComboBox::currentIndexChanged, this, &WidgetNodeAttachment::comboBoxJoint_currentIndexChanged);
}

WidgetNodeAttachment::~WidgetNodeAttachment()
{
    delete ui;
}

void WidgetNodeAttachment::setupNode(const QString &name)
{
    ui->lineEditTarget->setText(name);
    ui->lineEditPosX->setText("0");
    ui->lineEditPosY->setText("0");
    ui->lineEditPosZ->setText("0");
    ui->lineEditRotX->setText("0");
    ui->lineEditRotY->setText("0");
    ui->lineEditRotZ->setText("0");
    QStringList nodeList;
    QMapIterator<QString, std::shared_ptr<EntitySceneNode>> iter(Program::SceneNodeList);
    while (iter.hasNext())
    {
        iter.next();
        if (iter.value()->Type == "animation" && iter.value()->Name != name)
        {
            nodeList.append(iter.value()->Name);
        }
    }
    ui->comboBoxAnimation->blockSignals(true);
    ui->comboBoxAnimation->clear();
    ui->comboBoxAnimation->addItems(nodeList);
    ui->comboBoxAnimation->setCurrentIndex(-1);
    ui->comboBoxAnimation->blockSignals(false);
    ui->comboBoxJoint->clear();
    _selectedJoint.clear();
    AvatarLibrary::avatar_register("__GetJointNames", handleJointNames, this);
    AvatarLibrary::avatar_register("__GetJointLocal", handleJointLocal, this);
    std::shared_ptr<EntitySceneNode> node = Program::SceneNodeList[name];
    if (node)
    {
        for (qsizetype i = 0; i < node->ExtraScript.size(); i++)
        {
            // 解析当前附加信息
            if (node->ExtraScript[i].endsWith("#SetAttachment#"))
            {
                QString script = node->ExtraScript[i];
                qsizetype idx1 = script.indexOf("scene.handle('") + 14;
                qsizetype idx2 = script.indexOf("joint='") + 7;
                qsizetype idx3 = script.indexOf("translation_x=") + 14;
                qsizetype idx4 = script.indexOf("translation_y=") + 14;
                qsizetype idx5 = script.indexOf("translation_z=") + 14;
                qsizetype idx6 = script.indexOf("rotation_x=") + 11;
                qsizetype idx7 = script.indexOf("rotation_y=") + 11;
                qsizetype idx8 = script.indexOf("rotation_z=") + 11;
                QString param_animation = script.mid(idx1, script.indexOf('\'', idx1) - idx1);
                QString param_joint = script.mid(idx2, script.indexOf('\'', idx2) - idx2);
                QString param_translation_x = script.mid(idx3, script.indexOf(',', idx3) - idx3);
                QString param_translation_y = script.mid(idx4, script.indexOf(',', idx4) - idx4);
                QString param_translation_z = script.mid(idx5, script.indexOf(',', idx5) - idx5);
                QString param_rotation_x = script.mid(idx6, script.indexOf(',', idx6) - idx6);
                QString param_rotation_y = script.mid(idx7, script.indexOf(',', idx7) - idx7);
                QString param_rotation_z = script.mid(idx8, script.indexOf('}', idx8) - idx8);
                if (nodeList.contains(param_animation))
                {
                    _selectedJoint = param_joint;
                    ui->comboBoxAnimation->setCurrentText(param_animation);
                    ui->lineEditPosX->setText(param_translation_x);
                    ui->lineEditPosY->setText(param_translation_y);
                    ui->lineEditPosZ->setText(param_translation_z);
                    ui->lineEditRotX->setText(param_rotation_x);
                    ui->lineEditRotY->setText(param_rotation_y);
                    ui->lineEditRotZ->setText(param_rotation_z);
                    comboBoxAnimation_currentIndexChanged(ui->comboBoxAnimation->currentIndex());
                }
            }
        }
    }
}

void WidgetNodeAttachment::comboBoxAnimation_currentIndexChanged(int index)
{
    QString node = ui->comboBoxAnimation->currentText();
    if (!node.isEmpty())
    {
        AvatarLibrary::avatar_command(QString("engine.execute('__GetJointNames', scene.handle('%1','GetJointList'))").arg(node));
    }
}

void WidgetNodeAttachment::comboBoxJoint_currentIndexChanged(int index)
{
    QString node = ui->comboBoxAnimation->currentText();
    QString joint = ui->comboBoxJoint->currentText();
    if (!node.isEmpty() && !joint.isEmpty())
    {
        QStringList script;
        script.append(QString("local px,py,pz = scene.position('%1')").arg(ui->lineEditTarget->text()));
        script.append(QString("local ax,ay,az = scene.angle('%1')").arg(ui->lineEditTarget->text()));
        script.append(QString("local _px,_py,_pz,_ax,_ay,_az = scene.handle('%1','ToJointLocal',{joint='%2',translation_x=px,translation_y=py,translation_z=pz,rotation_x=ax,rotation_y=ay,rotation_z=az})").arg(node, joint));
        script.append(QString("engine.execute('__GetJointLocal', _px,_py,_pz,_ax,_ay,_az)"));
        AvatarLibrary::avatar_command(script.join('\n'));
    }
}

void WidgetNodeAttachment::on_pushButtonAdd_clicked()
{
    QString target = ui->lineEditTarget->text();
    QString animation = ui->comboBoxAnimation->currentText();
    QString joint = ui->comboBoxJoint->currentText();
    QString tx = ui->lineEditPosX->text();
    QString ty = ui->lineEditPosY->text();
    QString tz = ui->lineEditPosZ->text();
    QString ax = ui->lineEditRotX->text();
    QString ay = ui->lineEditRotY->text();
    QString az = ui->lineEditRotZ->text();
    if (target.isEmpty() || animation.isEmpty() || joint.isEmpty())
    {
        QMessageBox::warning(this, "错误", "不能为空");
        return;
    }
    std::shared_ptr<EntitySceneNode> node = Program::SceneNodeList[target];
    if (node)
    {
        QString format = "scene.handle('%1','SetAttachment',{joint='%2',node='%3',translation_x=%4,translation_y=%5,translation_z=%6,rotation_x=%7,rotation_y=%8,rotation_z=%9}) --#SetAttachment#";
        QString script = format.arg(animation, joint, target, tx, ty, tz, ax, ay, az);
        AvatarLibrary::avatar_command(script);
        for (qsizetype i = 0; i < node->ExtraScript.size(); i++)
        {
            if (node->ExtraScript[i].endsWith("#SetAttachment#")) node->ExtraScript.removeAt(i--);
        }
        node->ExtraScript.append(script);
    }
}

/**
 * @brief 获取骨骼名称列表回调
 * @param count
 * @param nameList
 * @param form
 * @return
 */
int WidgetNodeAttachment::handleJointNames(int count, const char** nameList, void* form)
{
    QStringList jointList;
    for (int i = 0; i < count; i++) jointList.append(nameList[i]);
    WidgetNodeAttachment* widget = static_cast<WidgetNodeAttachment*>(form);
    widget->ui->comboBoxJoint->blockSignals(true);
    widget->ui->comboBoxJoint->clear();
    widget->ui->comboBoxJoint->addItems(jointList);
    if (widget->_selectedJoint.isEmpty()) widget->ui->comboBoxJoint->setCurrentIndex(-1);
    else widget->ui->comboBoxJoint->setCurrentText(widget->_selectedJoint);
    widget->ui->comboBoxJoint->blockSignals(false);
    return 0;
}

/**
 * @brief 获取坐标转换到骨骼局部坐标系结果回调
 * @param transform
 * @param form
 * @return
 */
int WidgetNodeAttachment::handleJointLocal(int, const char** transform, void* form)
{
    WidgetNodeAttachment* widget = static_cast<WidgetNodeAttachment*>(form);
    widget->ui->lineEditPosX->setText(transform[0]);
    widget->ui->lineEditPosY->setText(transform[1]);
    widget->ui->lineEditPosZ->setText(transform[2]);
    widget->ui->lineEditRotX->setText(transform[3]);
    widget->ui->lineEditRotY->setText(transform[4]);
    widget->ui->lineEditRotZ->setText(transform[5]);
    return 0;
}
